Skip to content

fix(android): merge sideloaded subtitle tracks via MergingMediaSource; guard PiP activity lookup#4906

Open
WithakErik wants to merge 2 commits into
TheWidlarzGroup:support/6.x.xfrom
WithakErik:fix/android-subtitle-sideload-merging-media-source
Open

fix(android): merge sideloaded subtitle tracks via MergingMediaSource; guard PiP activity lookup#4906
WithakErik wants to merge 2 commits into
TheWidlarzGroup:support/6.x.xfrom
WithakErik:fix/android-subtitle-sideload-merging-media-source

Conversation

@WithakErik
Copy link
Copy Markdown

Problem

External subtitle/caption files passed via textTracks never appeared on Android. Two related bugs:

Bug 1 — Subtitles silently ignored
ProgressiveMediaSource.Factory (and the HLS/DASH variants) ignore MediaItem.SubtitleConfiguration entries entirely. Subtitles set via setSubtitleConfigurations are attached to the MediaItem but never loaded into MappedTrackInfo, so setSelectedTextTrack has nothing to select.

Reported in #4792 and #4614.

Bug 2 — PiP crash after subtitle change
findActivity() threw IllegalStateException when the ComponentActivity wasn't reachable through the ContextWrapper chain. This surface became more likely after the subtitle fix changes ExoPlayer's internal session/lifecycle state via MergingMediaSource.

Fix

Subtitle fix (ReactExoplayerView.java)

After the primary MediaSource is built, check for SubtitleConfiguration entries on the MediaItem. For each one, create a dedicated ProgressiveMediaSource backed by a SubtitleExtractor, then merge all sources with MergingMediaSource. This makes sideloaded tracks appear in MappedTrackInfo and respond to setSelectedTextTrack exactly like embedded tracks.

if (mediaItem.localConfiguration != null && !mediaItem.localConfiguration.subtitleConfigurations.isEmpty()) {
    // build one ProgressiveMediaSource per subtitle, merge with video source
    mediaSource = new MergingMediaSource(mergedSources);
}

PiP fix (PictureInPictureUtil.kt)

  • findActivity() now returns ComponentActivity? instead of throwing, with a ThemedReactContext.getCurrentActivity() fallback
  • All call sites updated to handle null with early returns
  • Replaces deprecated context.currentActivity field with context.getCurrentActivity()

Testing

Verified on a physical Android device (arm64-v8a) with external .vtt subtitle files. Subtitles now load and are selectable. PiP entry/exit no longer crashes after subtitles are active.

Closes #4792
Related: #4614

… lookup

ProgressiveMediaSource.Factory (and HLS/DASH variants) silently ignore
MediaItem.SubtitleConfiguration entries, so external subtitle/caption files
never appeared in MappedTrackInfo or responded to setSelectedTextTrack.

Fix: after the primary MediaSource is built, detect any SubtitleConfiguration
entries on the MediaItem, create a dedicated ProgressiveMediaSource for each
using SubtitleExtractor, and merge them all with MergingMediaSource. This
makes sideloaded tracks selectable exactly like embedded tracks.

Related: findActivity() previously threw IllegalStateException when the
ComponentActivity wasn't reachable through the ContextWrapper chain — a
condition that arises when PiP lifecycle events fire after the subtitle
MergingMediaSource changes the ExoPlayer session state. Make it return null
with a ThemedReactContext.getCurrentActivity() fallback; update all call
sites to handle null gracefully. Also replace the deprecated
context.currentActivity field with context.getCurrentActivity().

Fixes: external subtitles/captions not loading on Android (TheWidlarzGroup#4792, TheWidlarzGroup#4614)
…uard unsupported formats, preserve flags

Three improvements over the initial subtitle fix:

- Strip SubtitleConfigurations from the MediaItem before passing it to
  mediaSourceFactory so no factory variant (ProgressiveMediaSource,
  DefaultMediaSourceFactory, or plugin overrides) can create its own
  legacy subtitle sources alongside our MergingMediaSource. Prevents
  double-processing and the Media3 1.8 'Legacy decoding is disabled' crash
  that occurs when both paths are active.

- Check subtitleParserFactory.supportsFormat() before calling create().
  Previously an unknown mimeType would throw IllegalArgumentException at
  source creation time, killing playback entirely; now we log a warning
  and skip the unsupported track, matching DefaultMediaSourceFactory's
  behavior.

- Carry selectionFlags and roleFlags from SubtitleConfiguration onto the
  rebuilt Format so default/forced-caption auto-selection and preferred-
  role selection continue to work correctly.
@WithakErik
Copy link
Copy Markdown
Author

Updated with three hardening improvements (based on additional code review):

  • Strip subtitle configs from base MediaItem before passing to mediaSourceFactory — prevents any factory variant from also creating legacy subtitle sources alongside our MergingMediaSource, which would trigger the Media3 1.8 Legacy decoding is disabled crash
  • Guard unsupported formats via subtitleParserFactory.supportsFormat() before calling create() — unknown MIME types previously threw IllegalArgumentException at source creation time, killing playback; now we log a warning and skip the track, matching DefaultMediaSourceFactory's behavior
  • Preserve selectionFlags and roleFlags on the rebuilt Format so default/forced-caption auto-selection continues to work correctly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To Triage

Development

Successfully merging this pull request may close these issues.

1 participant